#ifndef AVALON_MULTICASTSOCKET_HPP
#define AVALON_MULTICASTSOCKET_HPP
#include "Avalon/IO/IO.hpp"
#include "Avalon/Network/DatagramPacket.hpp"
#include "Avalon/Threading/Async.hpp"

namespace boost {
namespace system {
  class error_code;
}
}

namespace Avalon {
namespace Network {

  /*! \class MulticastSocket
   *  \brief Represents a socket using the UDP with multicast protocol.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class MulticastSocket {
    public:

      //! Creates a MulticastSocket.
      /*!
        \param group The multicast group to join.
        \param interface The address of the interface to use.
      */
      MulticastSocket(const IpAddress& group, const IpAddress& interface);

      virtual ~MulticastSocket();

      //! Returns the receive buffer size.
      int GetReceiveBufferSize() const;

      //! Sets the receive buffer size.
      /*!
        \param size The size of set the receive buffer to.
      */
      void SetReceiveBufferSize(int size);

      //! Opens the socket to receive DatagramPackets.
      void Open();

      //! Closes the socket, ending reception of DatagramPackets.
      void Close();

      //! Receives a DatagramPacket from this socket.
      /*!
        \param buffer The Buffer to store the packet in.
        \return The DatagramPacket that was received.
      */
      Threading::Async<DatagramPacket>::Ptr Receive(IO::Buffer* buffer);

      //! Sends a DatagramPacket.
      /*!
        \param packet The DatagramPacket to send.
      */
      Threading::Async<void>::Ptr Send(const DatagramPacket& packet);

    private:
      struct SocketDetails;
      boost::recursive_mutex m_mutex;
      boost::scoped_ptr<SocketDetails> m_socketDetails;
      bool m_isOpen;
      int m_receiveBufferSize;

      void HandleRead(const Threading::AsyncOwner<DatagramPacket>::Ptr& packet,
        IO::Buffer* buffer, const boost::system::error_code& error,
        size_t size);
      void HandleWrite(const Threading::AsyncOwner<void>::Ptr& result,
        const IO::Buffer& buffer, const boost::system::error_code& error);
  };
}
}

#endif // AVALON_MULTICASTSOCKET_HPP
